﻿/*
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at
  http://www.mozilla.org/MPL/
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the
  License.
  
  The Original Code is [maashaack framework].
  
  The Initial Developers of the Original Code are
  Zwetan Kjukov <zwetan@gmail.com> and Marc Alcaraz <ekameleon@gmail.com>.
  Portions created by the Initial Developers are Copyright (C) 2004-2014
  the Initial Developers. All Rights Reserved.
  
  Contributor(s):
  
  Alternatively, the contents of this file may be used under the terms of
  either the GNU General Public License Version 2 or later (the "GPL"), or
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  in which case the provisions of the GPL or the LGPL are applicable instead
  of those above. If you wish to allow use of your version of this file only
  under the terms of either the GPL or the LGPL, and not to allow others to
  use your version of this file under the terms of the MPL, indicate your
  decision by deleting the provisions above and replace them with the notice
  and other provisions required by the LGPL or the GPL. If you do not delete
  the provisions above, a recipient may use your version of this file under
  the terms of any one of the MPL, the GPL or the LGPL.
*/
package molecule.render.flash.components.buttons
{
    import graphics.Align;
    import graphics.IFillStyle;
    import graphics.ILineStyle;
    import graphics.geom.EdgeMetrics;

    import molecule.events.ButtonEvent;

    import system.hack;

    import flash.display.Bitmap;
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
    import flash.display.InteractiveObject;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;
    import flash.text.AntiAliasType;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    
    use namespace hack ;
    
    /**
     * The builders of the BasicButton component.
     */
    public class BasicButtonBuilder extends CoreButtonBuilder 
    {
        /**
         * Creates a new BasicButtonBuilder instance.
         * @param target the target of the component reference to build.
         */
        public function BasicButtonBuilder( target:BasicButton = null)
        {
            super( target );
        }
        
        /**
         * Indicates the icon display reference.
         */
        public function get icon():DisplayObject
        {
            return _icon ;
        }
        
        /**
         * Attach a new icon in the component.
         */
        public function attachIcon( display:DisplayObject ):void
        {
            _icon = display ;
            var comp:BasicButton = target as BasicButton ;
            if( comp )
            {
                if( _icon )
                {
                    if ( _icon is InteractiveObject )
                    {
                        (_icon as InteractiveObject).mouseEnabled = false ;
                    }
                    comp.addChild( _icon ) ;
                }
                comp.update() ;
            }
        }
        
        /**
         * Clear the view of the component.
         */
        public override function clear():void 
        {
             //////////
             
             if( _target )
             {
                if( _textField && _target.contains( _textField ) )
                {
                    _target.removeChild( _textField ) ;
                }
             }
             
             //////////
             
             releaseIcon() ;
             
             //////////
             
             unregisterLoader() ;
             
             //////////
             
             _loader    = null ;
             _textField = null ;
        }
        
        /**
         * Invoked when the button is down.
         */
        public function disabled( e:ButtonEvent = null ):void
        {
            var comp:BasicButton = target as BasicButton ;
            if (comp )
            {
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    updateBackground( style.themeDisabled, style.themeBorderDisabled ) ;
                    if ( style.useTextColor && _textField )
                    {
                        _textField.textColor = style.textDisabled ;
                    }
                }
            }
        }
        
        /**
         * Invoked when the button is down.
         */
        public function down( e:ButtonEvent = null ):void
        {
            var comp:BasicButton = target as BasicButton ;
            if (comp )
            {
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    updateBackground( style.themeSelected, style.themeBorderSelected ) ;
                    if ( style.useTextColor && _textField )
                    {
                        _textField.textColor = style.textSelected ;
                    }
                }
            }
        }
        
        /**
         * Initialize all register type of this builder.
         */
        public override function initType():void
        {
            registerType( ButtonEvent.DISABLED , disabled ) ;
            registerType( ButtonEvent.DOWN     , down     ) ;
            registerType( ButtonEvent.OVER     , over     ) ;
            registerType( ButtonEvent.UP       , up       ) ;
        }
        
        /**
         * @private
         * Loads an external icon to create the view of the icon.
         */
        public function loadIcon( request:URLRequest ):void
        {
            if( request && _loader )
            {
                registerLoader() ;
                _loader.load( request ) ;
            }
            else
            {
                update() ;
            }
        }
        
        /**
         * Invoked when the button is over.
         */
        public function over( e:ButtonEvent = null ):void 
        {
            var comp:BasicButton = target as BasicButton ;
            if (comp )
            {
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    updateBackground( style.themeRollOver, style.themeBorderRollOver ) ;
                    if ( style.useTextColor && _textField )
                    {
                        _textField.textColor = style.textRollOver ;
                    }
                }
            }
        }
        
        /**
         * Release the current _icon reference.
         */
        public function releaseIcon():void
        {
            if( _loader )
            {
                try
                {
                    _loader.close() ;
                }
                catch( er:Error )
                {
                    //
                }
            }
            if( _icon )
            {
                if( _icon is Bitmap && (_icon as Bitmap).bitmapData )
                {
                    (_icon as Bitmap).bitmapData.dispose() ;
                }
                if ( target.contains( _icon ) )
                {
                    (target as DisplayObjectContainer).removeChild( _icon ) ;
                }
                _icon = null ;
            }
        }
        
        /**
          * Runs the build of the component.
         */
        public override function run( ...arguments:Array ):void
        {
            //////////
            
            _loader = new Loader() ;
            
            //////////
            
            _textField = new TextField() ;
            
            _textField.mouseEnabled = false ;
            
            //////////
            
            if( _target )
            {
               _target.addChild( _textField ) ;
            }
        }
        
        /**
         * Invoked when the button is up.
         */
        public function up( e:ButtonEvent = null ):void 
        {
            var comp:BasicButton = target as BasicButton ;
            if (comp )
            {
                updateBackground() ;
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    if ( style.useTextColor && _textField )
                    {
                        _textField.textColor = style.color ;
                    }
                }
            }
        }
        
        /**
         * Update the view of the component.
         */
        public override function update():void 
        {
            (target as BasicButton).invalidateDraw() ;
            
            updateField() ;
            updateBackground() ;
            updateIcon() ;
            
            updateLayout() ;
        }
        
        ////////////////
        
        /**
         * The icon reference of the component.
         */
        protected var _icon:DisplayObject ;
        
        /**
         * The loader of the builder.
         */
        protected var _loader:Loader ;
        
        /**
         * The field reference of the component.
         */
        protected var _textField:TextField ;
        
        /**
         * @private
         */
        protected function initializeIcon( e:Event ):void
        {
            unregisterLoader() ;
            attachIcon( _loader.content ) ;
        }
        
        /**
         * @private
         */
        public function registerLoader():void
        {
            if( _loader )
            {
                _loader.contentLoaderInfo.addEventListener( Event.INIT                        , initializeIcon ) ;
                _loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR             , initializeIcon ) ;
                _loader.contentLoaderInfo.addEventListener( SecurityErrorEvent.SECURITY_ERROR , initializeIcon ) ;
            }
        }
        
        /**
         * @private
         */
        public function unregisterLoader():void
        {
            if( _loader )
            {
                _loader.contentLoaderInfo.removeEventListener( Event.INIT                        , initializeIcon ) ;
                _loader.contentLoaderInfo.removeEventListener( IOErrorEvent.IO_ERROR             , initializeIcon ) ;
                _loader.contentLoaderInfo.removeEventListener( SecurityErrorEvent.SECURITY_ERROR , initializeIcon ) ;
            }
        }
        
        /**
         * Refresh the background.
         */
        protected function updateBackground( theme:IFillStyle=null , themeBorder:ILineStyle=null ):void
        {
            var comp:BasicButton = target as BasicButton ;
            if (comp )
            {
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    comp.lock() ;
                    
                    comp._align = style.align ;
                    comp.fill   = theme ? theme : ( comp._enabled ? ( comp._selected ? style.themeSelected : style.theme ) : style.themeDisabled ) ;
                    comp.line   = themeBorder ? themeBorder : ( comp._enabled ? ( comp._selected ? style.themeBorderSelected : style.themeBorder) : style.themeBorderDisabled ) ;
                    
                    comp.unlock() ;
                }
                
                comp.draw() ;
            }
        }
        
        /**
         * Refreshs the internal field.
         */
        protected function updateField():void
        {
            if( !_textField )
            {
                return ;
            }
            var comp:BasicButton = target as BasicButton ;
            if (comp )
            {
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    var padding:EdgeMetrics = style.padding ;
                    var txt:String = (comp.label != null) ? comp.label : "" ;
                    
                    _textField.width      = comp.w - padding.horizontal ;
                    _textField.height     = comp.h - padding.vertical ;
                    _textField.styleSheet = style.styleSheet ;
                    
                    _textField.antiAliasType = style.antiAliasType ? style.antiAliasType : AntiAliasType.NORMAL ;
                    _textField.autoSize      = style.autoSize ? style.autoSize : TextFieldAutoSize.NONE ;
                    _textField.border        = style.textBorder ;
                    _textField.borderColor   = style.textBorderColor ;
                    _textField.condenseWhite = style.condenseWhite;
                    _textField.embedFonts    = style.embedFonts ;
                    _textField.gridFitType   = style.gridFitType ;
                    _textField.multiline     = style.multiline ;
                    _textField.selectable    = style.selectable ;
                    _textField.thickness     = style.thickness ;
                    _textField.wordWrap      = style.wordWrap ;
                    
                    if ( style.html )
                    {
                        _textField.htmlText = txt ;
                    }
                    else
                    {    
                        _textField.text = txt ;
                    }
                    
                    _textField.visible = (txt != null ) && (txt != "") ;
                    
                    if ( style.useTextColor )
                    {
                        _textField.textColor = comp._enabled ? ( comp._selected ? style.textSelected : style.color ) : style.textDisabled ;
                    }
                }
            }
        }
        
        /**
         * Update the icon in the component.
         * @private
         */
        protected function updateIcon():void
        {
            var comp:BasicButton = target as BasicButton ;
            if( comp )
            {
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    if( _icon && _textField )
                    {
                        if( style.iconAutoSize )
                        {
                            _icon.height = comp.h - style.padding.vertical ;
                            _icon.scaleX = _icon.scaleY ;
                        }
                        else
                        {
                            _icon.scaleX = _icon.scaleY = 1 ;
                        }
                        
                        if( _textField )
                        {
                            _textField.width -= _icon.width ;
                            _textField.width -= style.iconMargin.horizontal ;
                            _textField.getCharBoundaries(0) ;
                        }
                        
                        comp.draw() ;
                    }
                }
            }
        }
        /**
         * Refreshs the elements.
         */
        protected function updateLayout():void
        {
            var comp:BasicButton = target as BasicButton ;
            if (comp )
            {
                var bounds:Rectangle = comp.fixArea() ;
                var style:BasicButtonStyle = comp.style as BasicButtonStyle ;
                if( style )
                {
                    var padding:EdgeMetrics = style.padding ;
                    
                    const $x:Number = bounds.x ;
                    const $y:Number = bounds.y ;
                    const $h:Number = comp.h ;
                    
                    if( _textField )
                    {
                        _textField.x = $x + padding.left ;
                        _textField.y = bounds.y ;
                        
                        switch( style._textVerticalAlign )
                        {
                            case Align.CENTER :
                            {
                                _textField.y += ($h - _textField.textHeight) / 2 ;
                                break ;
                            }
                            
                            case Align.BOTTOM :
                            {
                                _textField.y += $h - _textField.textHeight - padding.bottom ;
                                break ;
                            }
                            
                            default :
                            case Align.NONE :
                            case Align.TOP :
                            {
                                _textField.y += padding.top ;
                                break ;
                            }
                        }
                    }
                    
                    if( _icon && _textField )
                    {
                        var iconMargin:EdgeMetrics = style.iconMargin ;
                        switch( style.iconAlign )
                        {
                            case Align.NONE :
                            {
                                // do nothing
                                break ;
                            }
                            case Align.LEFT :
                            {
                                _icon.x = $x + iconMargin.left ;
                                _icon.y = $y + ($h - _icon.height) / 2 ;
                                _textField.x = _icon.x + _icon.width + iconMargin.right + padding.left ;
                                break ;
                            }
                            case Align.RIGHT :
                            {
                                _icon.x = _textField.x + _textField.width + padding.right + iconMargin.left ;
                                _icon.y = $y + ($h - _icon.height) / 2 ;
                                break ;
                            }
                            case Align.TOP_LEFT :
                            {
                                _icon.x = $x + iconMargin.left ;
                                _icon.y = $y + iconMargin.top ;
                                _textField.x = _icon.x + _icon.width + iconMargin.right + padding.left ;
                                break ;
                            }
                            case Align.TOP_RIGHT :
                            {
                                _icon.x = _textField.x + _textField.width + padding.right + iconMargin.left ;
                                _icon.y = $y + iconMargin.top ;
                                break ;
                            }
                            case Align.BOTTOM_LEFT :
                            {
                                _icon.x = $x + iconMargin.left ;
                                _icon.y = $y + $h - _icon.height - iconMargin.bottom ;
                                _textField.x = _icon.x + _icon.width + iconMargin.right + padding.left ;
                                break ;
                            }
                            case Align.BOTTOM_RIGHT :
                            {
                                _icon.x = _textField.x + _textField.width + padding.right + iconMargin.left ;
                                _icon.y = $y + $h - _icon.height - iconMargin.bottom ;
                                break ;
                            }
                        }
                    }
                }
            }
        }
    }
}
